namespace :fragment do
  desc "Populates molecules table with entries from flatfile KEGG/LIGAND database specified by argument directory"
  task :kegg, :directory, :needs => :environment do |t, args|
    kegg_directory = args.directory.nil? ? APP_CONFIG['kegg_dir'].starts_with?('/') ? APP_CONFIG['kegg_dir'] : File.join(RAILS_ROOT, APP_CONFIG['kegg_dir']) : args.directory
    raise "#{kegg_directory} not found." if not File.exists? kegg_directory

    puts "Processing kegg database entries from #{kegg_directory}"

    compound_filename = File.join(kegg_directory, "compound") # Path to compound file.
    mol_directory = File.join(kegg_directory, "mol")          # Path to molfile directory.
    entries = File.read(compound_filename).split("///")  # Extract entries from compound file.

    Rake::Task["db:truncate"].invoke("molecules")             # Truncate molecules table to avoid dublicate entries.

    # Process entries.
    entries.each do |entry|
      if entry =~ /^ENTRY\s+(C\d{5})(?:\s+.*){1,2}$\n (?# Matches compound entry number line.)
                   ^NAME((?:\s+.+;\n)*\s+.+)\n        (?# Matches compound name lines.)
                   (?:^FORMULA\s+(.+)$\n)?            (?# Matches compound formula line.)
                   (?:^MASS\s+(\d+(?:.\d+)?)$)?       (?# Matches compound mass line.)/x then
        begin 
          mol_filename = File.join(mol_directory, "#{$1.to_s}.mol") # Path to entry molfile.
          compound = $1.to_s
          names =  $2.to_s
          formula = $3.to_s
          mass = $4.to_s
          Molecule.create(:compound => compound,
                          :names => names.gsub!(/[ \t]*/, ''),
                          :formula => formula,
                          :mass => mass,
                          :mol_file => File.read(mol_filename)) if File.exists? mol_filename
        rescue
          $stderr.puts "Could not read molfile for compound " + String($1) + " in " + mol_filename + "."
        end 
      end
    end
    
    # Print task summary.
    puts "Processed " + String(entries.length) + " compounds from " + compound_filename + "."
    puts "Found " + String(Dir.entries(mol_directory).size - 2) + " molfiles at " + mol_directory + "."
    puts "Populated molecules table with " + String(Molecule.count) + " entries."
  end

  desc "Setups empty database and populates the molecules table."
  task :setup => ["db:drop", "db:create", "db:schema:load", "fragment:kegg"]
end

namespace :db do
  desc "Loads ActiveRecord database configuration."
  task :load_config => :environment do
    ActiveRecord::Base.configurations = Rails::Configuration.new.database_configuration
  end

  desc "Truncates table specified as argument."
  task :truncate, :table, :needs => :load_config do |t, args|
    raise "No table specified." if args.table.nil?
    begin
      config = ActiveRecord::Base.configurations[RAILS_ENV]
      ActiveRecord::Base.establish_connection
      case config["adapter"]
        when "mysql", "postgresql"
          ActiveRecord::Base.connection.execute("TRUNCATE #{args.table}")
        when "sqlite", "sqlite3"
          ActiveRecord::Base.connection.execute("DELETE FROM #{args.table}")
          ActiveRecord::Base.connection.execute("DELETE FROM sqlite_sequence where name='#{args.table}';")
      end
      ActiveRecord::Base.connection.execute("VACUUM #{args.table}")
    rescue
      $stderr.puts "Error while truncating. Make sure you have a valid database.yml file and have created the database" + 
                   "tables before running this command. Also make sure the table you are trying to truncate exists."
    end
  end

  desc "Setups database from scratch with test data."
  task :quicksetup => ["db:drop", "db:setup"]
end
